import time
import win32gui
import win32process
import win32api  # 这三个模块属于pywin32库，用于Windows API的功能调用，包括查找窗口、获取进程ID、操作进程等。
import ctypes  # 此模块允许Python程序调用C类型的函数，常用于与Windows DLL（动态链接库）交互，如本例中的kernel32.dll
import tkinter


def change_sun(hand, sun_num):
    sun_date = ctypes.c_long()
    # 创建一个 ctypes.c_long 类型的对象，并将其赋值给变量 sun_date。
    # ctypes 是 Python 的一个标准库，用于封装 C 语言类型的数据结构，并允许 Python 代码调用 C 库函数。
    # ctypes.c_long 是 ctypes 中的一个类型，代表 C 语言中的长整型
    kernel32.ReadProcessMemory(int(hand), 0x7578f8, ctypes.byref(sun_date), 4, None)
    # 用于从另一个进程中读取内存
    # BOOL ReadProcessMemory(
    #      HANDLE hProcess,                 进程句柄
    #      LPCVOID lpBaseAddress,           目标进程内存中的起始地址，想要从中读取数据。
    #      LPVOID lpBuffer,                 一个缓冲区，用于存放从目标进程中读取的数据。这个缓冲区必须在调用者进程中分配。
    #                                       把读取到的数据放到 sun_date2 这个变量所指向的内存位置
    #      SIZE_T nSize,                    要读取的字节数。
    #      SIZE_T * lpNumberOfBytesRead     输出参数，返回实际读取的字节数。可以为NULL
    # );

    sun_date2 = ctypes.c_long()
    kernel32.ReadProcessMemory(int(hand), sun_date.value + 0x868, ctypes.byref(sun_date2), 4, None)
    # .value用于获取该变量的实际值（即内存地址）。+ 0x868表示在sun_date指向的地址基础上偏移0x868个字节的位置
    new_sun_date = ctypes.c_long(sun_num)
    kernel32.WriteProcessMemory(int(hand), sun_date2.value + 0x5578, ctypes.byref(new_sun_date), 4, None)
    # 目的是向另一个进程的内存空间写入数据。
    # BOOL WriteProcessMemory(
    #     HANDLE hProcess,
    #     LPVOID lpBaseAddress,
    #     LPCVOID lpBuffer,
    #     SIZE_T nSize,
    #     SIZE_T * lpNumberOfBytesWritten  输出参数，返回实际写入的字节数。
    # );


def change_money(hand, money):
    money_date = ctypes.c_long()
    kernel32.ReadProcessMemory(int(hand), 0x7578f8, ctypes.byref(money_date), 4, None)
    kernel32.ReadProcessMemory(int(hand), money_date.value + 0x94C, ctypes.byref(money_date), 4, None)
    new_money_date = ctypes.c_long(money)
    kernel32.WriteProcessMemory(int(hand), money_date.value + 0x50, ctypes.byref(new_money_date), 4, None)


def change_plants(hand, cooling):
    for i in range(0, 20):
        time.sleep(0.5)
        cooling_data = ctypes.c_long()
        kernel32.ReadProcessMemory(int(hand), 0x7578f8, ctypes.byref(cooling_data), 4, None)
        kernel32.ReadProcessMemory(int(hand), cooling_data.value + 0x868, ctypes.byref(cooling_data), 4, None)
        kernel32.ReadProcessMemory(int(hand), cooling_data.value + 0x150, ctypes.byref(cooling_data), 4, None)
        new_cooling_date = ctypes.c_long(cooling)
        kernel32.WriteProcessMemory(int(hand), cooling_data.value + 0x28, ctypes.byref(new_cooling_date), 4, None)


def change_cooling(hand, cooling):
    for i in range(0, 20):
        time.sleep(0.5)  # 程序暂停，控制速度
        qqqq = 4
        cooling_data = ctypes.c_long()
        kernel32.ReadProcessMemory(int(hand), 0x7578f8, ctypes.byref(cooling_data), qqqq, None)
        kernel32.ReadProcessMemory(int(hand), cooling_data.value + 0x868, ctypes.byref(cooling_data), qqqq, None)
        kernel32.ReadProcessMemory(int(hand), cooling_data.value + 0x15c, ctypes.byref(cooling_data), qqqq, None)
        # kernel32.ReadProcessMemory(int(Phand),cooling_data.value,ctypes.byref(cooling_data),4,None)
        new_cooling_date = ctypes.c_long(cooling)
        kernel32.WriteProcessMemory(int(hand), cooling_data.value + 0x70, ctypes.byref(new_cooling_date), qqqq, None)
        kernel32.WriteProcessMemory(int(hand), cooling_data.value + 0xC0, ctypes.byref(new_cooling_date), qqqq, None)
        kernel32.WriteProcessMemory(int(hand), cooling_data.value + 0x110, ctypes.byref(new_cooling_date), qqqq, None)
        kernel32.WriteProcessMemory(int(hand), cooling_data.value + 0x160, ctypes.byref(new_cooling_date), qqqq, None)
        kernel32.WriteProcessMemory(int(hand), cooling_data.value + 0x1B0, ctypes.byref(new_cooling_date), qqqq, None)
        kernel32.WriteProcessMemory(int(hand), cooling_data.value + 0x200, ctypes.byref(new_cooling_date), qqqq, None)
        kernel32.WriteProcessMemory(int(hand), cooling_data.value + 0x2A0, ctypes.byref(new_cooling_date), qqqq, None)
        kernel32.WriteProcessMemory(int(hand), cooling_data.value + 0x250, ctypes.byref(new_cooling_date), qqqq, None)
        kernel32.WriteProcessMemory(int(hand), cooling_data.value + 0x2F0, ctypes.byref(new_cooling_date), qqqq, None)
        kernel32.WriteProcessMemory(int(hand), cooling_data.value + 0x340, ctypes.byref(new_cooling_date), qqqq, None)


def change_tree(hand, tree):
    tree_data = ctypes.c_long()
    kernel32.ReadProcessMemory(int(hand), 0x7578f8, ctypes.byref(tree_data), 4, None)
    kernel32.ReadProcessMemory(int(hand), tree_data.value + 0x94C, ctypes.byref(tree_data), 4, None)
    new_tree_date = ctypes.c_long(1000 + tree)
    kernel32.WriteProcessMemory(int(hand), tree_data.value + 0x258, ctypes.byref(new_tree_date), 4, None)


def change_fertilizer(hand, fertilizer):
    fertilizer_data = ctypes.c_long()
    kernel32.ReadProcessMemory(int(hand), 0x7578f8, ctypes.byref(fertilizer_data), 4, None)
    kernel32.ReadProcessMemory(int(hand), fertilizer_data.value + 0x94c, ctypes.byref(fertilizer_data), 4, None)
    new_fertilizer_date = ctypes.c_long(1000 + fertilizer)
    kernel32.WriteProcessMemory(int(hand), fertilizer_data.value + 0x220, ctypes.byref(new_fertilizer_date), 4, None)


def change_insecticide(hand, insecticide):
    insecticide_data = ctypes.c_long()
    kernel32.ReadProcessMemory(int(hand), 0x7578f8, ctypes.byref(insecticide_data), 4, None)
    kernel32.ReadProcessMemory(int(hand), insecticide_data.value + 0x94C, ctypes.byref(insecticide_data), 4, None)
    new_insecticide_data = ctypes.c_long(1000 + insecticide)
    kernel32.WriteProcessMemory(int(hand), insecticide_data.value + 0x224, ctypes.byref(new_insecticide_data), 4, None)


def change_chotolate(hand, chotolate):
    chotolate_data = ctypes.c_long()
    kernel32.ReadProcessMemory(int(hand), 0x7578f8, ctypes.byref(chotolate_data), 4, None)
    kernel32.ReadProcessMemory(int(hand), chotolate_data.value + 0x94C, ctypes.byref(chotolate_data), 4, None)
    new_chotolate_date = ctypes.c_long(1000 + chotolate)
    kernel32.WriteProcessMemory(int(hand), chotolate_data.value + 0x250, ctypes.byref(new_chotolate_date), 4, None)


def change():
    # 调用修改函数
    # print("1:修改阳光\n")
    # print("2:修改金币\n")
    # print("3:修改巧克力\n")
    # print("4:修改智慧树肥料\n")
    # print("5:修改普通肥料\n")
    # print("6:修改杀虫剂\n")
    # print("7:修改植物\n")
    # print("8:修改成无冷却\n")
    # number_change = input("请输入序号")
    # if number_change == "1":
    #     change_sun(hand, int(input("请输入所需要的阳光：")))
    # elif number_change == "2":
    #     change_money(hand, int(input("请输入所需要的金币：")))
    # elif number_change == "3":
    #     change_chotolate(hand, int(input("请输入所需要的蜗牛巧克力：")))
    # elif number_change == "4":
    #     change_tree(hand, int(input("请输入所需要的智慧树肥料：")))
    # elif number_change == "5":
    #     change_fertilizer(hand, int(input("请输入所需要的普通肥料：")))
    # elif number_change == "6":
    #     change_insecticide(hand, int(input("请输入所需要的杀虫剂：")))
    # elif number_change == "7":
    #     change_plants(hand, int(input("请输入想要修改的植物")))
    # elif number_change == "8":
    #     change_cooling(hand, 1)
    # return change()
    window = tkinter.Tk()
    window.title('植物大战僵尸修改器')
    window.geometry('600x600')
    var = tkinter.StringVar()
    l = tkinter.Label(window, bg='green', font=('Arial', 12), width=100, height=2, text='empty')
    l.pack()
    e = tkinter.Entry(window, show=None)
    e.pack()

    def work():
        if var.get() == '所需的阳光':
            change_sun(hand, int(e.get()))
        elif var.get() == '所需的金币/10':
            change_money(hand, int(e.get()))
        elif var.get() == '所需的蜗牛巧克力':
            change_chotolate(hand, int(e.get()))
        elif var.get() == '所需的智慧树肥料':
            change_tree(hand, int(e.get()))
        elif var.get() == '所需的普通肥料':
            change_fertilizer(hand, int(e.get()))
        elif var.get() == '所需的杀虫剂':
            change_insecticide(hand, int(e.get()))
        elif var.get() == '修改的植物，0代表豌豆射手，以此类推，48代表模仿者':
            change_plants(hand, int(e.get()))
        elif var.get() == '修改的状态，1代表无冷却，0代表无限冷却':
            change_cooling(hand, int(e.get()))

    def print_selection():
        l.config(text='请输入' + var.get())

    rd1 = tkinter.Radiobutton(window, text='修改阳光', variable=var, value='所需的阳光', command=print_selection,
                              width=12, height=2)
    rd1.pack()
    rd2 = tkinter.Radiobutton(window, text='修改金币', variable=var, value='所需的金币/10', command=print_selection,
                              width=12, height=2)
    rd2.pack()
    rd3 = tkinter.Radiobutton(window, text='修改蜗牛巧克力', variable=var, value='所需的蜗牛巧克力',
                              command=print_selection, width=12, height=2)
    rd3.pack()
    rd4 = tkinter.Radiobutton(window, text='修改智慧树肥料', variable=var, value='所需的智慧树肥料',
                              command=print_selection, width=12, height=2)
    rd4.pack()
    rd5 = tkinter.Radiobutton(window, text='修改普通肥料', variable=var, value='所需的普通肥料',
                              command=print_selection, width=12, height=2)
    rd5.pack()
    rd6 = tkinter.Radiobutton(window, text='修改杀虫剂', variable=var, value='所需的杀虫剂', command=print_selection,
                              width=12, height=2)
    rd6.pack()
    rd7 = tkinter.Radiobutton(window, text='修改植物', variable=var,
                              value='修改的植物，0代表豌豆射手，以此类推，48代表模仿者', command=print_selection, width=12,
                              height=2)
    rd7.pack()
    rd8 = tkinter.Radiobutton(window, text='修改冷却', variable=var, value='修改的状态，1代表无冷却，0代表无限冷却',
                              command=print_selection, width=12, height=2)
    rd8.pack()
    b = tkinter.Button(window, text="启动！！！", width=24, height=2, command=work)
    b.pack()
    window.mainloop()
    # return change()


if __name__ == '__main__':
    kernel32 = ctypes.windll.LoadLibrary('kernel32.dll')
    # 从Windows系统中加载名为kernel32.dll的动态链接库（Dynamic Link Library），并将其引用赋值给变量kernel32
    # 这样就可以通过kernel32变量来访问kernel32.dll库中导出的所有函数。
    # kernel32.dll是Windows操作系统的核心库之一，包含了大量用于与操作系统交互的基本函数，
    # 如内存管理、进程和线程控制、文件和I/O操作、错误处理等

    PROCESS_ALL_ACCESS = (0x000F0000 | 0x00100000 | 0xFFF)
    # 在Windows API中，访问权限是通过位标志（bit flags）来定义的，每个位对应一种特定的访问权限。
    # 通过按位或运算符|组合这些位标志，可以请求多种权限。
    # 0x000F0000 和 0x00100000分别代表了某些特定的高阶权限位，但具体哪些权限由这些位控制可能需要查阅Windows
    # API文档的最新定义，因为具体的权限分配可能会随着操作系统版本的不同而有所变化。
    # 0xFFF通常代表了低阶权限的组合。在32位系统中，这可能涵盖了基本地读、写、执行等权限，但在不同上下文中具体含义可能有差异。
    windos_handle = win32gui.FindWindow(None, "Plants vs. Zombies 1.2.0.1073 RELEASE")
    # 用于在Windows系统中查找一个窗口。如果找到，FindWindow函数会返回一个窗口句柄（HWND，一个独一无二的标识符），
    # 这个句柄可以在后续操作中用来与该窗口进行交互，比如获取窗口的位置、大小，或者发送消息给窗口等。
    if not windos_handle:
        print("Window not found.")
        exit(1)
    read, pid = win32process.GetWindowThreadProcessId(windos_handle)
    # 于根据提供的窗口句柄（HWND）获取与该窗口相关的线程ID和进程ID。以便后续可以打开该进程并进行内存操作，比如修改游戏内的数据。
    hand = win32api.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
    # win32api.OpenProcess: 它用于根据给定的进程ID打开一个进程。win32api模块提供了对Windows API的直接访问。
    # False: 这个布尔参数表示是否继承句柄。当设置为False时，表示新开的进程句柄不会被新创建的子进程继承。
    # 使用之前得到的进程ID打开目标进程，并获取一个具有所有访问权限的进程句柄，存储在变量phand中，为接下来可能的内存读写或其他高级进程操作做准备。
    change()
    win32api.CloseHandle(hand)
    # 关闭句柄
